/*
 * Copyright (c) 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.libermundi.theorcs.chronicles.model;

import java.util.SortedSet;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
import org.libermundi.theorcs.chronicles.ChronicleConstants;
import org.libermundi.theorcs.chronicles.model.sheet.Sheet;
import org.libermundi.theorcs.core.model.Gender;
import org.libermundi.theorcs.core.model.Searchable;
import org.libermundi.theorcs.core.model.base.Labelable;
import org.libermundi.theorcs.core.tapestry.util.Groupable;
import org.libermundi.theorcs.security.model.UidUserStatefulEntity;
import org.libermundi.theorcs.security.model.User;

import com.google.common.collect.Sets;

@Entity(name="Persona")
@Table(name=ChronicleConstants.TBL_PERSONA)
@Indexed(index="Persona")
@Analyzer(definition = "SuggestionAnalyzer")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public final class Persona extends UidUserStatefulEntity implements Labelable, Groupable, Comparable<Persona>, Searchable {
	public final static String PROP_NAME="name";
	public final static String PROP_PLAYER="player";
	public final static String PROP_CHRONICLE="chronicle";
	public final static String PROP_SHEET="sheet";
	public final static String PROP_PICTURE="picture";
	public final static String PROP_DEFAULT="defaultPerso";
	public static final String PROP_DESCRIPTION = "description";
	public static final String PROP_BACKGROUND = "background";
	public static final String PROP_HIDDENINFOS = "hiddeninfos";
	public static final String PROP_AGE = "age";
	public static final String PROP_GENDER = "gender";
	public static final String PROP_FACTIONS = "factions";
	
	private static final String[] SEARCHABLE_FIELDS = new String[]{PROP_NAME, PROP_DESCRIPTION};

	private static final long serialVersionUID = 4117055951776711672L;

	private String _name;
	private User _player;
	private Chronicle _chronicle;
	private Sheet _sheet;
	private String _picture;
	private String _description;
	private String _background;
	private String _hiddenInfos;
	private int _age = 0;
	private Gender _gender = Gender.DONTSAY; 
	private boolean _default;
	private SortedSet<Faction> _factions = Sets.newTreeSet();
	private Faction _defaultFaction;
	
	@Basic
	@Column(name = Persona.PROP_NAME, length=50, nullable=false)
	@Field(store=Store.YES,index=Index.YES)
	public String getName() {
		return _name;
	}
	
	@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
	@JoinColumn(name="sheetId")
	public Sheet getSheet() {
		return _sheet;
	}

	@ManyToOne(cascade = CascadeType.ALL,fetch=FetchType.LAZY)
	@JoinColumn(name="playerId")
	public User getPlayer() {
		return _player;
	}

	@ManyToOne(cascade = CascadeType.ALL,fetch=FetchType.LAZY)
	@JoinColumn(name="chronicleId")
	public Chronicle getChronicle() {
		return _chronicle;
	}
	
	@Enumerated(EnumType.STRING)
	@Column(name=Persona.PROP_GENDER,length=7,nullable=true)
	public Gender getGender() {
		return _gender;
	}
	
	@Basic
	@Column(name=Persona.PROP_AGE,nullable=true)
	public int getAge() {
		return _age;
	}
	
	@Basic
	@Column(name=Persona.PROP_PICTURE,length=255,nullable=true)
	public String getPicture() {
		return _picture;
	}
	
	@Lob
	@Column(name=Persona.PROP_DESCRIPTION,nullable=true)
	@Field(store=Store.YES,index=Index.YES)
	public String getDescription() {
		return _description;
	}	
	
	@Lob
	@Column(name=Persona.PROP_BACKGROUND,nullable=true)
	public String getBackground() {
		return _background;
	}	
	
	@Lob
	@Column(name=Persona.PROP_HIDDENINFOS,nullable=true)
	public String getHiddenInfos() {
		return _hiddenInfos;
	}
	
	@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
	@JoinTable(name = ChronicleConstants.TBL_PERSONA2FACTION,
		joinColumns = { @JoinColumn(name = "personaId") },
		inverseJoinColumns = { @JoinColumn(name = "factionId") }
	)
	@Sort(type=SortType.NATURAL)
	public SortedSet<Faction> getFactions() {
		return _factions;
	}
	
	@ManyToOne(fetch=FetchType.LAZY, optional=false)
	@JoinColumn(name="defaultFactionid")
	public Faction getDefaultFaction() {
		return _defaultFaction;
	}
	
	/**
	 * @return the true if this Persona is the default for the User
	 */
	@Column(name = Persona.PROP_DEFAULT)
	public boolean isDefaultPerso() {
		return _default;
	}	
	
	public void setName(String name) {
		_name=name;
	}

	public void setPlayer(User player) {
		_player=player;
	}

	public void setChronicle(Chronicle chronicle) {
		_chronicle=chronicle;
	}

	public void setSheet(Sheet sheet) {
		_sheet=sheet;
	} 
	
	public void setPicture(String picture) {
		_picture = picture;
	}

	public void setDescription(String description) {
		_description = description;
	}

	public void setBackground(String background) {
		_background = background;
	}

	public void setHiddenInfos(String hiddenInfos) {
		_hiddenInfos = hiddenInfos;
	}
	
	public void setAge(int age){
		_age = age;
	}

	public void setGender(Gender gender){
		_gender = gender;
	}

	public void setFactions(SortedSet<Faction> factions){
		_factions = factions;
	}
	
	public void setDefaultFaction(Faction defaultFaction) {
		_defaultFaction = defaultFaction;
	}	
	/*
	 * (non-Javadoc)
	 * @see org.libermundi.theorcs.core.model.base.Labelable#printLabel()
	 */
	@Override
	public String printLabel() {
		return getName();
	}

	/**
	 * @param isDefault the default to set
	 */
	public void setDefaultPerso(boolean isDefault) {
		this._default = isDefault;
	}

	/*
	 * (non-Javadoc)
	 * @see org.libermundi.theorcs.security.model.UserStatefulEntity#toString()
	 */
	@Override
	public String toString() {
		return "Perso [name=" + getName() + ", player=" + getPlayer().getUsername() + ", chronicle=" + getChronicle().getTitle() + "]";
	}

	/* (non-Javadoc)
	 * @see java.lang.Comparable#compareTo(java.lang.Object)
	 */
	@Override
	public int compareTo(Persona other) {
		if(other == null || other.getName() == null){
			return -1;
		}
		
		if(getName() == null) {
			return 1;
		}
		
		return getName().compareTo(other.getName());
	}

	/* (non-Javadoc)
	 * @see org.libermundi.theorcs.core.model.Searchable#loadSearchfields()
	 */
	@Override
	public String[] loadSearchfields() {
		return SEARCHABLE_FIELDS;
	}

	/* (non-Javadoc)
	 * @see org.libermundi.theorcs.core.tapestry.util.Groupable#printGroupLabel()
	 */
	@Override
	public String printGroupLabel() {
		return getFactions().first().printLabel();
	}
}
